package com.chen.base.config;

import cn.hutool.core.util.StrUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.env.PropertiesPropertySourceLoader;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.PathResource;
import org.springframework.core.io.Resource;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 扩展配置文件
 * 在配置文件中添加：extend-configs=./redis.yml,./*.yml,./*.properties,classpath:*.yml
 * @author ~龙~
 */
@Slf4j
@Order(Integer.MIN_VALUE + 20)
public class ExtendPropertySourceConfig implements EnvironmentPostProcessor {

    private static Boolean isLoad = false;
    private final PropertiesPropertySourceLoader propertiesLoader = new PropertiesPropertySourceLoader();
    private final YamlPropertySourceLoader yamlLoader = new YamlPropertySourceLoader();

    /** 公共配置(*) **/
    public MapPropertySource commonConfig(){
        Map<String, Object> map = new HashMap<>();
        map.put("spring.aop.auto", true);
        map.put("server.shutdown", "graceful");
        map.put("spring.lifecycle.timeout-per-shutdown-phase", "60s");

        return new MapPropertySource("commonConfig", map);
    }

    @Override
    @SneakyThrows
    public void postProcessEnvironment(ConfigurableEnvironment env, SpringApplication application) {
        // 避免EnvironmentPostProcessor执行多次的问题
        if (ExtendPropertySourceConfig.isLoad){
            return;
        }
        ExtendPropertySourceConfig.isLoad = true;
        env.getPropertySources().addLast(commonConfig());

        // 遍历加载配置
        List<String> configList = ergodicConfig(env, "extend-configs");
        for (String configFile : configList) {
            // 判断配置文件路径信息
            Resource resource;
            if (configFile.contains("classpath")){
                configFile = configFile.substring(configFile.indexOf(":") + 1);
                resource = new ClassPathResource(configFile);
            }else {
                resource = new PathResource(configFile);
            }
            if (!resource.exists()) {
                throw new IllegalArgumentException("配置 " + resource + " 不存在!!!");
            }

            try {
                // 判断配置文件类型
                PropertySource<?> propertySource;
                String filename = resource.getFilename();
                if (filename.contains(".yml")){
                    propertySource = yamlLoader.load(filename, resource).get(0);
                }else {
                    propertySource = propertiesLoader.load(filename, resource).get(0);
                }
                // 添加配置（优先级低）
                env.getPropertySources().addLast(propertySource);
                System.out.println("加载配置 -> " + resource);
            } catch (Exception ex) {
                throw new IllegalStateException("加载扩展配置错误 -> " + resource, ex);
            }
        }
    }

    private List<String> ergodicConfig(ConfigurableEnvironment environment, String key){
        // 遍历加载配置
        int index = 0;
        List<String> configList = new ArrayList<>();
        while (index != -1){
            String value = environment.getProperty(StrUtil.format("{}[{}]", key, index));
            if (StrUtil.isNotBlank(value)){
                ++index;
                configList.add(value);
            }else {
                index = -1;
            }
        }
        String configValue = environment.getProperty(key);
        if (StrUtil.isNotBlank(configValue)){
            configList.add(configValue);
        }

        return configList;
    }
}
